#include "CodeEditorSettings.h"
#include "CodeEditor/CodeEditorConstants.h"

#include "CodeEditor.h"
#include "BehaviorSettings.h"
#include "CompletionSettings.h"
#include "DisplaySettings.h"
#include "StorageSettings.h"
#include "TabSettings.h"
#include "Config/EditorSettingsPage.h"
//+#include "BehaviorSettingsPage.h"
//#include "DisplaySettingsPage.h"
//#include "FontSettingsPage.h"
//#include "HighlighterSettingsPage.h"

#include <QtGui/QApplication>

using namespace CodeEdit;
using namespace CodeEdit::Constants;
using namespace CodeEdit::Internal;

namespace CodeEdit {
namespace Internal {

class TextEditorSettingsPrivate
{
public:
    EditorSettingsPage *_editorSettingsPage;
//+    FontSettingsPage *_fontSettingsPage;
//    BehaviorSettingsPage *_behaviorSettingsPage;
//    DisplaySettingsPage *_displaySettingsPage;
//    HighlighterSettingsPage *_highlighterSettingsPage;

    CompletionSettings _completionSettings;

    void fontZoomRequested(int pointSize);
    void zoomResetRequested();
};

void TextEditorSettingsPrivate::fontZoomRequested(int zoom)
{
    FontSettings &fs = const_cast<FontSettings&>(_fontSettingsPage->fontSettings());
    fs.setFontZoom(qMax(10, fs.fontZoom() + zoom));
    _fontSettingsPage->saveSettings();
}

void TextEditorSettingsPrivate::zoomResetRequested()
{
    FontSettings &fs = const_cast<FontSettings&>(_fontSettingsPage->fontSettings());
    fs.setFontZoom(100);
    _fontSettingsPage->saveSettings();
}

} // namespace Internal
} // namespace CodeEdit


CodeEditorSettings *CodeEditorSettings::_instance = 0;

CodeEditorSettings::CodeEditorSettings(QObject *parent)
    : QObject(parent)
    , _d(new Internal::TextEditorSettingsPrivate)
{
    if (_instance)
        return;

    _instance = this;

    ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();

    // Note: default background colors are coming from FormatDescription::background()

    // Add font preference page
    FormatDescriptions formatDescriptions;
    formatDescriptions.append(FormatDescription(QLatin1String(C_TEXT), tr("Text")));

    // Special categories
    const QPalette p = QApplication::palette();
    formatDescriptions.append(FormatDescription(QLatin1String(C_LINK), tr("Link"), Qt::blue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_SELECTION), tr("Selection"), p.color(QPalette::HighlightedText)));
    formatDescriptions.append(FormatDescription(QLatin1String(C_LINE_NUMBER), tr("Line Number")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_SEARCH_RESULT), tr("Search Result")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_SEARCH_SCOPE), tr("Search Scope")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_PARENTHESES), tr("Parentheses")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_CURRENT_LINE), tr("Current Line")));

    FormatDescription currentLineNumber = FormatDescription(QLatin1String(C_CURRENT_LINE_NUMBER), tr("Current Line Number"), Qt::darkGray);
    currentLineNumber.format().setBold(true);
    formatDescriptions.append(currentLineNumber);

    formatDescriptions.append(FormatDescription(QLatin1String(C_OCCURRENCES), tr("Occurrences")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_OCCURRENCES_UNUSED), tr("Unused Occurrence")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_OCCURRENCES_RENAME), tr("Renaming Occurrence")));

    // Standard categories
    formatDescriptions.append(FormatDescription(QLatin1String(C_NUMBER), tr("Number"), Qt::darkBlue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_STRING), tr("String"), Qt::darkGreen));
    formatDescriptions.append(FormatDescription(QLatin1String(C_TYPE), tr("Type"), Qt::darkMagenta));
    formatDescriptions.append(FormatDescription(QLatin1String(C_KEYWORD), tr("Keyword"), Qt::darkYellow));
    formatDescriptions.append(FormatDescription(QLatin1String(C_OPERATOR), tr("Operator")));
    formatDescriptions.append(FormatDescription(QLatin1String(C_PREPROCESSOR), tr("Preprocessor"), Qt::darkBlue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_LABEL), tr("Label"), Qt::darkRed));
    formatDescriptions.append(FormatDescription(QLatin1String(C_COMMENT), tr("Comment"), Qt::darkGreen));
    formatDescriptions.append(FormatDescription(QLatin1String(C_DOXYGEN_COMMENT), tr("Doxygen Comment"), Qt::darkBlue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_DOXYGEN_TAG), tr("Doxygen Tag"), Qt::blue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_VISUAL_WHITESPACE), tr("Visual Whitespace"), Qt::lightGray));
    formatDescriptions.append(FormatDescription(QLatin1String(C_DISABLED_CODE), tr("Disabled Code")));

    // Diff categories
    formatDescriptions.append(FormatDescription(QLatin1String(C_ADDED_LINE), tr("Added Line"), QColor(0, 170, 0)));
    formatDescriptions.append(FormatDescription(QLatin1String(C_REMOVED_LINE), tr("Removed Line"), Qt::red));
    formatDescriptions.append(FormatDescription(QLatin1String(C_DIFF_FILE), tr("Diff File"), Qt::darkBlue));
    formatDescriptions.append(FormatDescription(QLatin1String(C_DIFF_LOCATION), tr("Diff Location"), Qt::blue));

    _d->_fontSettingsPage = new FontSettingsPage(formatDescriptions,
                                                 QLatin1String(Constants::TEXT_EDITOR_FONT_SETTINGS),
                                                 this);
    pm->addObject(_d->_fontSettingsPage);

    // Add the GUI used to configure the tab, storage and interaction settings
    CodeEdit::BehaviorSettingsPageParameters behaviorSettingsPageParameters;
    behaviorSettingsPageParameters.id = QLatin1String(Constants::TEXT_EDITOR_BEHAVIOR_SETTINGS);
    behaviorSettingsPageParameters.displayName = tr("Behavior");
    behaviorSettingsPageParameters.settingsPrefix = QLatin1String("text");
    _d->_behaviorSettingsPage = new BehaviorSettingsPage(behaviorSettingsPageParameters, this);
    pm->addObject(_d->_behaviorSettingsPage);

    CodeEdit::DisplaySettingsPageParameters displaySettingsPageParameters;
    displaySettingsPageParameters.id = QLatin1String(Constants::TEXT_EDITOR_DISPLAY_SETTINGS),
    displaySettingsPageParameters.displayName = tr("Display");
    displaySettingsPageParameters.settingsPrefix = QLatin1String("text");
    _d->_displaySettingsPage = new DisplaySettingsPage(displaySettingsPageParameters, this);
    pm->addObject(_d->_displaySettingsPage);

    _d->_highlighterSettingsPage =
        new HighlighterSettingsPage(QLatin1String(Constants::TEXT_EDITOR_HIGHLIGHTER_SETTINGS), this);
    pm->addObject(_d->_highlighterSettingsPage);

    connect(_d->_fontSettingsPage, SIGNAL(changed(CodeEdit::FontSettings)),
            this, SIGNAL(fontSettingsChanged(CodeEdit::FontSettings)));
    connect(_d->_behaviorSettingsPage, SIGNAL(tabSettingsChanged(CodeEdit::TabSettings)),
            this, SIGNAL(tabSettingsChanged(CodeEdit::TabSettings)));
    connect(_d->_behaviorSettingsPage, SIGNAL(storageSettingsChanged(CodeEdit::StorageSettings)),
            this, SIGNAL(storageSettingsChanged(CodeEdit::StorageSettings)));
    connect(_d->_behaviorSettingsPage, SIGNAL(behaviorSettingsChanged(CodeEdit::BehaviorSettings)),
            this, SIGNAL(behaviorSettingsChanged(CodeEdit::BehaviorSettings)));
    connect(_d->_displaySettingsPage, SIGNAL(displaySettingsChanged(CodeEdit::DisplaySettings)),
            this, SIGNAL(displaySettingsChanged(CodeEdit::DisplaySettings)));

    // TODO: Move these settings to CodeEdit category
    if (QSettings *s = Core::ICore::instance()->settings())
        _d->_completionSettings.fromSettings(QLatin1String("CppTools/"), s);
}

CodeEditorSettings::~CodeEditorSettings()
{
    ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
    pm->removeObject(_d->_fontSettingsPage);
    pm->removeObject(_d->_behaviorSettingsPage);
    pm->removeObject(_d->_displaySettingsPage);
    pm->removeObject(_d->_highlighterSettingsPage);

    delete _d;

    _instance = 0;
}

CodeEditorSettings *CodeEditorSettings::instance()
{
    return _instance;
}

/**
 * Initializes editor settings. Also connects signals to keep them up to date
 * when they are changed.
 */
void CodeEditorSettings::initializeEditor(BaseTextEditor *editor)
{
    // Connect to settings change signals
    connect(this, SIGNAL(fontSettingsChanged(CodeEdit::FontSettings)),
            editor, SLOT(setFontSettingsIfVisible(CodeEdit::FontSettings)));
    connect(this, SIGNAL(tabSettingsChanged(CodeEdit::TabSettings)),
            editor, SLOT(setTabSettings(CodeEdit::TabSettings)));
    connect(this, SIGNAL(storageSettingsChanged(CodeEdit::StorageSettings)),
            editor, SLOT(setStorageSettings(CodeEdit::StorageSettings)));
    connect(this, SIGNAL(behaviorSettingsChanged(CodeEdit::BehaviorSettings)),
            editor, SLOT(setBehaviorSettings(CodeEdit::BehaviorSettings)));
    connect(this, SIGNAL(displaySettingsChanged(CodeEdit::DisplaySettings)),
            editor, SLOT(setDisplaySettings(CodeEdit::DisplaySettings)));
    connect(this, SIGNAL(completionSettingsChanged(CodeEdit::CompletionSettings)),
            editor, SLOT(setCompletionSettings(CodeEdit::CompletionSettings)));

    connect(editor, SIGNAL(requestFontZoom(int)),
            this, SLOT(fontZoomRequested(int)));
    connect(editor, SIGNAL(requestZoomReset()),
            this, SLOT(zoomResetRequested()));

    // Apply current settings (tab settings depend on font settings)
    editor->setFontSettings(fontSettings());
    editor->setTabSettings(tabSettings());
    editor->setStorageSettings(storageSettings());
    editor->setBehaviorSettings(behaviorSettings());
    editor->setDisplaySettings(displaySettings());
    editor->setCompletionSettings(completionSettings());
}


const FontSettings &CodeEditorSettings::fontSettings() const
{
    return _d->_fontSettingsPage->fontSettings();
}

const TabSettings &CodeEditorSettings::tabSettings() const
{
    return _d->_behaviorSettingsPage->tabSettings();
}

const StorageSettings &CodeEditorSettings::storageSettings() const
{
    return _d->_behaviorSettingsPage->storageSettings();
}

const BehaviorSettings &CodeEditorSettings::behaviorSettings() const
{
    return _d->_behaviorSettingsPage->behaviorSettings();
}

const DisplaySettings &CodeEditorSettings::displaySettings() const
{
    return _d->_displaySettingsPage->displaySettings();
}

const CompletionSettings &CodeEditorSettings::completionSettings() const
{
    return _d->_completionSettings;
}

const HighlighterSettings &CodeEditorSettings::highlighterSettings() const
{
    return _d->_highlighterSettingsPage->highlighterSettings();
}

void CodeEditorSettings::setCompletionSettings(const CodeEdit::CompletionSettings &settings)
{
    if (_d->_completionSettings == settings)
        return;

    _d->_completionSettings = settings;
    if (QSettings *s = Core::ICore::instance()->settings())
        _d->_completionSettings.toSettings(QLatin1String("CppTools/"), s);

    emit completionSettingsChanged(_d->_completionSettings);
}

//- #include "moc_CodeEditorSettings.cpp"
